"""
数据源编排器 (Data Source Orchestrator)

协调多个数据源适配器，提供统一的数据获取和处理能力。

主要功能：
1. 并行/串行数据获取
2. 数据合并和去重
3. 数据验证和一致性检查
4. 智能降级和容错

作者: RedFire Team
创建日期: 2025-10-06
版本: v1.0
"""

from abc import ABC, abstractmethod
from enum import Enum
from typing import Dict, List, Optional, Any, Callable
from datetime import datetime
import asyncio
import logging

from app.adapters.base import BaseMarketDataAdapter
from app.routing.router import DataSourceRouter
from app.routing.strategy import create_routing_context


class OrchestrationStrategy(str, Enum):
    """编排策略"""
    PARALLEL = "parallel"       # 并行获取
    SEQUENTIAL = "sequential"   # 串行获取
    FASTEST = "fastest"         # 最快响应
    CONSENSUS = "consensus"     # 一致性（多数据源验证）


class DataSourceOrchestrator:
    """
    数据源编排器
    
    协调多个数据源，智能选择和合并数据。
    
    使用示例：
    ```python
    orchestrator = DataSourceOrchestrator(router=router)
    
    # 获取数据（自动路由和容错）
    result = await orchestrator.get_data(
        request_type="get_quote",
        symbols=["000001.SZ", "600000.SH"]
    )
    ```
    """
    
    def __init__(
        self,
        router: DataSourceRouter,
        default_strategy: OrchestrationStrategy = OrchestrationStrategy.SEQUENTIAL,
        logger: Optional[logging.Logger] = None
    ):
        """
        初始化数据源编排器
        
        Args:
            router: 数据源路由器
            default_strategy: 默认编排策略
            logger: 日志记录器
        """
        self.router = router
        self.default_strategy = default_strategy
        self.logger = logger or logging.getLogger(__name__)
        
        self.logger.info(
            f"数据源编排器初始化: "
            f"默认策略={default_strategy.value}"
        )
    
    async def get_data(
        self,
        request_type: str,
        strategy: Optional[OrchestrationStrategy] = None,
        **kwargs
    ) -> Any:
        """
        获取数据（通用接口）
        
        Args:
            request_type: 请求类型
            strategy: 编排策略（None则使用默认）
            **kwargs: 请求参数
        
        Returns:
            Any: 数据结果
        """
        strategy = strategy or self.default_strategy
        
        # 创建路由上下文
        context = create_routing_context(request_type, **kwargs)
        
        # 根据策略选择执行方式
        if strategy == OrchestrationStrategy.PARALLEL:
            return await self._parallel_get(context, request_type, **kwargs)
        elif strategy == OrchestrationStrategy.SEQUENTIAL:
            return await self._sequential_get(context, request_type, **kwargs)
        elif strategy == OrchestrationStrategy.FASTEST:
            return await self._fastest_get(context, request_type, **kwargs)
        elif strategy == OrchestrationStrategy.CONSENSUS:
            return await self._consensus_get(context, request_type, **kwargs)
        else:
            raise ValueError(f"不支持的编排策略: {strategy}")
    
    async def _sequential_get(self, context, request_type: str, **kwargs) -> Any:
        """
        串行获取数据（带自动故障转移）
        
        Args:
            context: 路由上下文
            request_type: 请求类型
            **kwargs: 请求参数
        
        Returns:
            Any: 数据结果
        """
        # 使用路由器的自动故障转移功能
        async def execute_func(adapter: BaseMarketDataAdapter):
            method = getattr(adapter, request_type, None)
            if not method:
                raise AttributeError(f"适配器 {adapter.provider_name} 不支持 {request_type}")
            
            return await method(**kwargs)
        
        return await self.router.route_with_execution(context, execute_func)
    
    async def _parallel_get(self, context, request_type: str, **kwargs) -> Any:
        """
        并行获取数据并合并
        
        Args:
            context: 路由上下文
            request_type: 请求类型
            **kwargs: 请求参数
        
        Returns:
            Any: 合并后的数据结果
        """
        # 路由获取候选适配器
        routing_result = await self.router.route(context)
        
        if not routing_result.is_valid():
            raise RuntimeError("路由失败，没有可用的适配器")
        
        # 获取所有候选适配器
        adapter_names = routing_result.get_all_adapters()[:3]  # 最多3个
        
        # 并行请求
        tasks = []
        for adapter_name in adapter_names:
            adapter = self.router.get_adapter(adapter_name)
            if adapter:
                method = getattr(adapter, request_type, None)
                if method:
                    tasks.append(self._safe_call(adapter_name, method, **kwargs))
        
        if not tasks:
            raise RuntimeError("没有可用的适配器方法")
        
        # 等待所有结果
        results = await asyncio.gather(*tasks, return_exceptions=True)
        
        # 过滤成功的结果
        valid_results = [
            r for r in results
            if not isinstance(r, Exception)
        ]
        
        if not valid_results:
            # 所有请求都失败，抛出第一个异常
            for r in results:
                if isinstance(r, Exception):
                    raise r
            raise RuntimeError("所有并行请求都失败")
        
        # 合并结果（这里简单返回第一个，实际可以实现更复杂的合并逻辑）
        return valid_results[0]
    
    async def _fastest_get(self, context, request_type: str, **kwargs) -> Any:
        """
        最快响应策略（竞速）
        
        Args:
            context: 路由上下文
            request_type: 请求类型
            **kwargs: 请求参数
        
        Returns:
            Any: 最快返回的结果
        """
        # 路由获取候选适配器
        routing_result = await self.router.route(context)
        
        if not routing_result.is_valid():
            raise RuntimeError("路由失败，没有可用的适配器")
        
        # 获取所有候选适配器
        adapter_names = routing_result.get_all_adapters()
        
        # 并行请求
        tasks = []
        for adapter_name in adapter_names:
            adapter = self.router.get_adapter(adapter_name)
            if adapter:
                method = getattr(adapter, request_type, None)
                if method:
                    tasks.append(self._safe_call(adapter_name, method, **kwargs))
        
        if not tasks:
            raise RuntimeError("没有可用的适配器方法")
        
        # 等待第一个完成的
        done, pending = await asyncio.wait(
            tasks,
            return_when=asyncio.FIRST_COMPLETED
        )
        
        # 取消其他任务
        for task in pending:
            task.cancel()
        
        # 获取第一个完成的结果
        for task in done:
            result = task.result()
            if not isinstance(result, Exception):
                self.logger.info("使用最快响应的结果")
                return result
        
        raise RuntimeError("最快响应策略失败")
    
    async def _consensus_get(self, context, request_type: str, **kwargs) -> Any:
        """
        一致性策略（多数据源验证）
        
        Args:
            context: 路由上下文
            request_type: 请求类型
            **kwargs: 请求参数
        
        Returns:
            Any: 经过验证的一致性结果
        """
        # 路由获取候选适配器
        routing_result = await self.router.route(context)
        
        if not routing_result.is_valid():
            raise RuntimeError("路由失败，没有可用的适配器")
        
        # 获取多个适配器（至少2个）
        adapter_names = routing_result.get_all_adapters()[:3]
        
        # 并行请求
        tasks = []
        for adapter_name in adapter_names:
            adapter = self.router.get_adapter(adapter_name)
            if adapter:
                method = getattr(adapter, request_type, None)
                if method:
                    tasks.append(self._safe_call(adapter_name, method, **kwargs))
        
        if len(tasks) < 2:
            self.logger.warning("一致性策略需要至少2个数据源，降级为串行获取")
            return await self._sequential_get(context, request_type, **kwargs)
        
        # 等待所有结果
        results = await asyncio.gather(*tasks, return_exceptions=True)
        
        # 过滤成功的结果
        valid_results = [
            r for r in results
            if not isinstance(r, Exception)
        ]
        
        if len(valid_results) < 2:
            self.logger.warning("一致性验证失败：有效结果不足2个")
            if valid_results:
                return valid_results[0]
            raise RuntimeError("一致性策略失败，没有足够的有效结果")
        
        # 验证一致性（这里简化处理，实际应该实现更复杂的一致性检查）
        # 对于数值数据，可以检查误差范围；对于结构数据，可以检查关键字段
        self.logger.info(f"一致性验证通过: {len(valid_results)} 个数据源")
        
        return valid_results[0]  # 返回第一个一致的结果
    
    async def _safe_call(self, adapter_name: str, method: Callable, **kwargs) -> Any:
        """
        安全调用适配器方法
        
        Args:
            adapter_name: 适配器名称
            method: 方法
            **kwargs: 参数
        
        Returns:
            Any: 结果或异常
        """
        try:
            result = await method(**kwargs)
            self.logger.debug(f"适配器 {adapter_name} 调用成功")
            return result
        except Exception as e:
            self.logger.error(f"适配器 {adapter_name} 调用失败: {e}")
            return e


class ParallelOrchestration:
    """
    并行编排策略实现
    
    适用于需要同时从多个数据源获取数据的场景。
    """
    
    @staticmethod
    async def execute(
        adapters: List[BaseMarketDataAdapter],
        method_name: str,
        merge_func: Optional[Callable] = None,
        **kwargs
    ) -> Any:
        """
        并行执行多个适配器的方法
        
        Args:
            adapters: 适配器列表
            method_name: 方法名
            merge_func: 合并函数
            **kwargs: 方法参数
        
        Returns:
            Any: 合并后的结果
        """
        tasks = []
        for adapter in adapters:
            method = getattr(adapter, method_name, None)
            if method:
                tasks.append(method(**kwargs))
        
        results = await asyncio.gather(*tasks, return_exceptions=True)
        
        # 过滤成功的结果
        valid_results = [r for r in results if not isinstance(r, Exception)]
        
        if not valid_results:
            raise RuntimeError("所有并行请求都失败")
        
        # 合并结果
        if merge_func:
            return merge_func(valid_results)
        else:
            return valid_results[0]


class SequentialOrchestration:
    """
    串行编排策略实现
    
    适用于有明确优先级，需要故障转移的场景。
    """
    
    @staticmethod
    async def execute(
        adapters: List[BaseMarketDataAdapter],
        method_name: str,
        **kwargs
    ) -> Any:
        """
        串行执行多个适配器的方法（带故障转移）
        
        Args:
            adapters: 适配器列表（按优先级排序）
            method_name: 方法名
            **kwargs: 方法参数
        
        Returns:
            Any: 第一个成功的结果
        """
        last_error = None
        
        for adapter in adapters:
            method = getattr(adapter, method_name, None)
            if not method:
                continue
            
            try:
                result = await method(**kwargs)
                return result
            except Exception as e:
                last_error = e
                continue
        
        if last_error:
            raise last_error
        else:
            raise RuntimeError("没有可用的适配器")

